package com.zone.domain.strategy.service.armory.assemble.impl;

import com.google.common.collect.Maps;
import com.google.common.collect.Range;
import com.zone.domain.strategy.model.entity.StrategyAwardEntity;
import com.zone.domain.strategy.repository.IStrategyRepository;
import com.zone.domain.strategy.service.armory.assemble.IStrategyAssembleHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

/**
 * @author: zongzi
 * @description: 抽象策略装配父类，实现装配逻辑
 * @date: 2024/5/29
 */
@Slf4j
@Service
public abstract class AbstractStrategyAssembleHandler implements IStrategyAssembleHandler {
    @Autowired
    private IStrategyRepository strategyRepository;


    /**
     * 装配策略：将策略明细存入缓存中
     *
     * @param key                   缓存key中的一部分
     * @param strategyAwardEntities 策略明细
     */
    public final void assemble(String key, List<StrategyAwardEntity> strategyAwardEntities) {
        // 获取小数位最小的概率(去除小数位尾数为0，0.2500 => 0.25)
        BigDecimal minFractionalPart = strategyAwardEntities.stream()
                .map(StrategyAwardEntity::getAwardRate)
                .map(awardRate -> awardRate.remainder(BigDecimal.ONE).stripTrailingZeros())
                .min(BigDecimal::compareTo)
                .orElse(BigDecimal.ZERO);

        // 获取最小计算单元（0.1 -> 10, 0.01 -> 100...）
        int minUnit = 1;
        for (int i = 0; i < minFractionalPart.scale(); i++) {
            minUnit = minUnit * 10;
        }

        // 范围
        int range = 0;
        // 将每一个范围对应的奖品id存入Map中
        Map<Range<Integer>, Integer> awardRangeTable = Maps.newHashMap();
        // 计算每一个奖品概率对应的(打乱奖品明细集合)
        for (StrategyAwardEntity strategyAwardEntity : strategyAwardEntities) {
            Integer awardId = strategyAwardEntity.getAwardId();
            BigDecimal awardRate = strategyAwardEntity.getAwardRate();
            // 每个奖品概率占用总概率的份额
            BigDecimal occupyPortion = awardRate.multiply(BigDecimal.valueOf(minUnit)).setScale(0, RoundingMode.CEILING);
            // 范围集合(range, newRange]
            Range<Integer> rateRange = Range.openClosed(range, range + occupyPortion.intValue());
            awardRangeTable.put(rateRange, awardId);
            // 重新计算范围
            range += occupyPortion.intValue();
        }

        // 将奖品集合存入缓存中
        strategyRepository.storeStrategyAwardTable(key, awardRangeTable);
    }
}
